package com.an.store;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.HexUtil;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;

// 存储文件解密
public class CommitLogTest {

    public static void main(String[] args) throws IOException {
        String fileName_or_phyficalOffset = "00000000002147483648";
        Path path = Paths.get("E:\\tmp\\rocketmq-data-log\\broker-a-0\\data\\store\\commitlog", fileName_or_phyficalOffset);
        FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
        // 设大一点，尽量一次读取完一条消息的完整字节。
        ByteBuffer byteBuffer = ByteBuffer.allocate(2048);

        fileChannel.read(byteBuffer);
        // 输出commitLog的信息

        byteBuffer.flip();
        // 记录消息总长度，每一次操作记录一次，最终与读取的消息总长度对比
        int totalLength = 0;
        int totalLengthF = byteBuffer.getInt();

        println("TOTALSIZE，该消息总长度4字节",totalLengthF);
        totalLength+=4;


        byte[] magic = new byte[4];
        byteBuffer.get(magic);
        println("MAGICCODE，魔数，4字节，固定值0xdaa320a7",HexUtil.encodeHexStr(magic));
        totalLength+=4;

        readByte2Str(byteBuffer,"BODYCRC，消息体CRC校验码，4字节",4);
        totalLength+=4;

        println("QUEUEID，消息消费队列ID，4字节",byteBuffer.getInt());
        totalLength+=4;


        readByte2Str(byteBuffer,"//FLAG，消息Flag，ROcketMQ不做处理，供用户自定义使用默认4字节。",4);
        totalLength+=4;


        println("QUEUEOFFSET，消息在消息消费队列的偏移量8字节",byteBuffer.getLong());
        totalLength+=8;

        println("PHYSICALOFFSET，消息在消息消费队列的偏移量",byteBuffer.getLong());
        totalLength+=8;
        System.out.println("文件名:" + fileName_or_phyficalOffset);

        ////SYSFLAG，消息系统Flag，例如是否压缩、是否是事务消息等，4字节
        // 不知具体的原始类型。。。。
        readByte2Str(byteBuffer,"//SYSFLAG，消息系统Flag，例如是否压缩、是否是事务消息等，4字节",4);
        totalLength+=4;

        //  8 //BORNTIMESTAMP，生产者调用消息发送API的时间戳，8字节。
        long bornTimestamp = byteBuffer.getLong();
        String timePattern = "yyyy-MM-dd HH:mm:ss.sss";
        println("BORNTIMESTAMP，生产者调用消息发送API的时间戳，8字节。",DateUtil.date(bornTimestamp).toString(timePattern));
        totalLength+=8;

        // bornhostLength //BORNHOST，消息发送者IP、端口号，8字节
        byte[] ipbyte4s = new byte[4];
        byteBuffer.get(ipbyte4s);
        println("bornhostLength //BORNHOST，消息发送者IP、端口号，8字节---------->IP",Arrays.toString(ipbyte4s));
        println("bornhostLength //BORNHOST，消息发送者IP、端口号，8字节---------->PORT",byteBuffer.getInt());
        totalLength+=8;

        // //STORETIMESTAMP，消息存储时间戳8字节。
        long storeTimestamp = byteBuffer.getLong();
        println("//STORETIMESTAMP，消息存储时间戳8字节。",DateUtil.date(storeTimestamp).toString(timePattern));
        totalLength+=8;

        // storehostAddressLength //STOREHOSTADDRESS，Broker服务器IP+端口号，8字节
        byte[] ipByte = new byte[4];
        byteBuffer.get(ipByte);
        println("storehostAddressLength //STOREHOSTADDRESS，Broker服务器IP+端口号，8字节.---->IP", Arrays.toString(ipByte));
        int port = byteBuffer.getInt();
        println("storehostAddressLength //STOREHOSTADDRESS，Broker服务器IP+端口号，8字节.---->PORT",port);
        totalLength+=8;

        //  //RECONSUMETIMES，消息重试次数，4字节。
        int retryTimes = byteBuffer.getInt();
        println("RECONSUMETIMES，消息重试次数，4字节",retryTimes);
        totalLength+=4;


        // Prepared Transaction Offset事务消息物理偏移量8字节
        println("Prepared Transaction Offset事务消息物理偏移量8字节",byteBuffer.getLong());
        totalLength+=8;

        // 4 + (bodyLength > 0 ? bodyLength : 0) //BODY，消息体长度（定义4字节）+ 消息长度
        int bodyLength = byteBuffer.getInt();
        println("4 + (bodyLength > 0 ? bodyLength : 0) //BODY，消息体长度（定义4字节）+ 消息长度.----->内容长度",bodyLength);
        readByte2StrNormalPrint(byteBuffer,"4 + (bodyLength > 0 ? bodyLength : 0) //BODY，消息体长度（定义4字节）+ 消息长度.----->内容",bodyLength);
        totalLength+=4+bodyLength;


        // 1 + topicLength //TOPIC，主题存储长度1字节，主题内容长度
        System.out.println("----------------------");
        byte topicLen = byteBuffer.get();
        System.out.println("1 + topicLength //TOPIC，主题存储长度1字节，主题内容长度------->topic的长度：" + (int)topicLen);
        readByte2StrNormalPrint(byteBuffer,"1 + topicLength //TOPIC，主题存储长度1字节，主题内容长度---->topic",(int)topicLen);
        totalLength+=1+(int)topicLen;


        //2 + (propertiesLength > 0 ? propertiesLength : 0) //propertiesLength，消息属性长度，表示消息属性长度不能超过65536个字符
        short propertyLen = byteBuffer.getShort();
        System.out.println("----------------------");
        System.out.println("2 + (propertiesLength > 0 ? propertiesLength : 0) //propertiesLength，消息属性长度，表示消息属性长度不能超过65536个字符,长度：" + propertyLen);
        readByte2StrNormalPrint(byteBuffer,"2 + (propertiesLength > 0 ? propertiesLength : 0) //propertiesLength，消息属性长度，表示消息属性长度不能超过65536个字符,内容",(int)propertyLen);
        totalLength+=2+propertyLen;

        System.out.println("------------------------------一条消息探索完毕------------------------------------");
        System.out.println("消息长度（文件,totalLengthF）："+ totalLengthF );
        System.out.println("消息长度（计算,totalLength）：" + totalLength);


        fileChannel.close();

    }

    public static void readByte2Str(ByteBuffer byteBuffer,String key,int len){
        byte[] value = new byte[len];
        byteBuffer.get(value);
        println(key,new String(value));
    }

    public static void readByte2StrNormalPrint(ByteBuffer byteBuffer,String key,int len){
        byte[] value = new byte[len];
        byteBuffer.get(value);
        printlnNormal(key,new String(value));
    }

    public static void println(String key,Object value){
        System.out.println("--------------------");
        System.out.println("Key["+key+"],value["+value+"]");
    }

    public static void printlnNormal(String key,Object value){
        System.out.println("Key["+key+"],value["+value+"]");
    }

}
